package top.z.work.framework.web.interceptor;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.extra.spring.SpringUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;

/**
 * API访问日志Interceptor
 */
@Slf4j
public class ApiAccessLogInterceptor implements HandlerInterceptor {

    public static final String PROD_PROFILE = "prod";

    public static final String ATTRIBUTE_HANDLER_METHOD = "HANDLER_METHOD";

    private static final String ATTRIBUTE_STOP_WATCH = "ApiAccessLoggerInterceptor.StopWatch";

    @Override
    public boolean preHandle(
            @NonNull HttpServletRequest request,
            @NonNull HttpServletResponse response,
            @NonNull Object handler
    ) {
        // 记录 HandlerMethod, 提供给 LoggerAccessFilter 使用
        HandlerMethod method = handler instanceof HandlerMethod ? (HandlerMethod) handler : null;
        if (method != null) {
            request.setAttribute(ATTRIBUTE_HANDLER_METHOD, method);
        }

        // 打印 request 日志
        if (!PROD_PROFILE.equals(SpringUtil.getActiveProfile())) {
            log.info("[preHandle][开始请求 URL({})]", request.getRequestURI());
            // 计时
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            request.setAttribute(ATTRIBUTE_STOP_WATCH, stopWatch);
            // 打印 Controller 路径
            printHandlerMethodPosition(method);
        }

        return true;
    }

    @Override
    public void afterCompletion(
            @NonNull HttpServletRequest request,
            @NonNull HttpServletResponse response,
            @NonNull Object handler,
            Exception ex
    ) {
        // 打印 response 日志
        if (!PROD_PROFILE.equals(SpringUtil.getActiveProfile())) {
            StopWatch stopWatch = (StopWatch) request.getAttribute(ATTRIBUTE_STOP_WATCH);
            stopWatch.stop();
            log.info("[afterCompletion][完成请求 URL({}) 耗时({} ms)]", request.getRequestURI(), stopWatch.getTotalTimeMillis());
        }
    }

    /**
     * 打印 Controller 方法路径
     */
    private void printHandlerMethodPosition(HandlerMethod handlerMethod) {
        if (handlerMethod == null) {
            return;
        }
        Method   method = handlerMethod.getMethod();
        Class<?> clazz  = method.getDeclaringClass();
        try {
            // 获取 method 的 lineNumber
            List<String> clazzContents = FileUtil.readUtf8Lines(ResourceUtil.getResource(null, clazz).getPath().replace("/target/classes/", "/src/main/java/") + clazz.getSimpleName() + ".java");
            Optional<Integer> lineNumber = IntStream.range(0, clazzContents.size())
                    .filter(i -> clazzContents.get(i).contains(" " + method.getName() + "(")) // 简单匹配, 不考虑方法重名
                    .mapToObj(i -> i + 1) // 行号从 1 开始
                    .findFirst();
            if (lineNumber.isEmpty()) {
                return;
            }
            // 打印结果
            log.info("Controller: {}({}.java:{})", clazz.getName(), clazz.getSimpleName(), lineNumber.get());
        } catch (Exception ignore) {
        }
    }

}
